package com.wmd.core.util;


import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @description:树形结构数据
 * @author: luyincheng
 * @date: 2021/1/18 9:10
 */
public class TreeStructure<T> {
    /// <summary>
    /// 节点类型
    /// </summary>
//    public Class<?> NodeIdType;
    /// <summary>
    /// 父节点类型
    /// </summary>
//    public Class<?> PNodeIdType;

    //public TreeStructure(T node,string NodeIdName,string PNodeIdName)
    public TreeStructure(T node) {
        this.node = node;
//        this.NodeIdType = Integer.class;
//        this.PNodeIdType = Integer.class;

    }
    public TreeStructure() {
    }

    public T getNode() {
        return node;
    }

    /// <summary>
    /// 当前节点
    /// </summary>
    public T node;
    /// <summary>
    /// 子节点
    /// </summary>
    public List<TreeStructure<T>> childs;
    //额外信息
    public Object extra;


    public void addChild(TreeStructure<T> child) {
        if (childs == null) {
            childs = new ArrayList<TreeStructure<T>>();
        }
        this.childs.add(child);
    }

    public static <T, TKey> List<TreeStructure<T>> init(List<T> nodes, Function<? super T, ? extends TKey> NodeId, Function<? super T, ? extends TKey> PNodeID, String rootID) {
        if (rootID == null || "".equals(rootID.trim())) {
            rootID = "0";
        }

        List<TreeStructure<T>> trees = new ArrayList<TreeStructure<T>>();
        //尝试按规则初始化树
        for (T t : nodes) {
            if (PNodeID.apply(t) == null || rootID.equals(NodeId.apply(t).toString()) || (rootID.equals("0") && "0".equals(PNodeID.apply(t).toString()))) {
                TreeStructure<T> root = new TreeStructure<T>(t);
                findChilds(root, nodes, NodeId, PNodeID);
                trees.add(root);
            }
        }
        //如果未成功，采用查找父节点确定根节点
        if(trees.size()<=0){
            for (T t : nodes) {
                if (findParent(t,nodes,NodeId, PNodeID)==null) {
                    TreeStructure<T> root = new TreeStructure<T>(t);
                    findChilds(root, nodes, NodeId, PNodeID);
                    trees.add(root);
                }
            }
        }
        return trees;
    }

    public static <T, TKey> void findChilds(TreeStructure<T> root, List<T> nodes, Function<? super T, ? extends TKey> NodeId, Function<? super T, ? extends TKey> PNodeID) {
        for (T t : nodes) {
            if (PNodeID.apply(t) != null && NodeId.apply(root.node).toString().equals(PNodeID.apply(t).toString())) {
                TreeStructure<T> child = new TreeStructure<T>(t);
                findChilds(child, nodes, NodeId, PNodeID);
                root.addChild(child);
            }
        }

    }
    public static <T, TKey> T findParent(T cnode, List<T> nodes, Function<? super T, ? extends TKey> NodeId, Function<? super T, ? extends TKey> PNodeID) {
        Object PNodeIdObj=PNodeID.apply(cnode);
        if(PNodeIdObj==null){
            return null;
        }
        for (T t : nodes) {
            if (NodeId.apply(t).toString().equals(PNodeIdObj.toString())) {
                return  t;
            }
        }
        return null;
    }

    public static <T, TKey> T findRoot(T cnode, List<T> nodes, Function<? super T, ? extends TKey> NodeId, Function<? super T, ? extends TKey> PNodeID) {
        Object PNodeIdObj=PNodeID.apply(cnode);
        if(PNodeIdObj==null){
            return cnode;
        }
        for (T t : nodes) {
            if (NodeId.apply(t).toString().equals(PNodeIdObj.toString())) {
                return  findRoot(t,nodes,NodeId,PNodeID);
            }
        }
        return cnode;
    }
    public static <T, TKey> boolean isParent(TKey cnodeId,TKey pnodeId, List<T> nodes, Function<? super T, ? extends TKey> NodeId, Function<? super T, ? extends TKey> PNodeID) {
        if(cnodeId==null||pnodeId==null){
            return false;
        }

        T cnode=null;
        for (T t : nodes) {
            if (NodeId.apply(t).toString().equals(cnodeId.toString())) {
                cnode=t;
            }
        }
        if(cnode==null){
            return false;
        }

        Object PNodeIdObj=PNodeID.apply(cnode);
        if(PNodeIdObj==null){
            return false;
        }
        if(PNodeIdObj.toString().equals(pnodeId.toString())){
            return true;
        }else{
            T currentPnode=findParent(cnode,nodes,NodeId,PNodeID);
            if(currentPnode==null){
                return false;
            }
            return isParent(NodeId.apply(currentPnode),pnodeId,nodes,NodeId,PNodeID);
        }
    }

    public static <T, TKey> void sortTreeNode(List<TreeStructure<T>> source, Function<? super T, ? extends TKey> sortKey) {

        if (source == null || source.size() <= 0) {
            return;
        }

        source.sort((p1, p2) ->
        {
            String d1 = sortKey.apply(p1.node) != null ? sortKey.apply(p1.node).toString() : "0";
            String d2 = sortKey.apply(p2.node) != null ? sortKey.apply(p2.node).toString() : "0";
            return d1.compareTo(d2);
        });
        for (TreeStructure<T> item : source) {
            sortTreeNode(item.childs, sortKey);
        }
    }
    public <TKey> void  sortTreeNode(Function<? super T, ? extends TKey> sortKey) {
        if(this.childs!=null){
            sortTreeNode(this.childs, sortKey);
        }
    }
}
